<?php
namespace Member\ORG;

class Wechat {
	
	//ACCESS_TOKEN
	public  $token;
	//微信接口地址
	private $apiUri = 'https://api.weixin.qq.com/cgi-bin/';
	private $appid;
	private $app_id;
	private $app_secret;
	private $error;
	function __construct($appid) {
		$this->appid = $appid;
		$app = M('WechatApp')->find($appid);
		$this->app_id     = $app['appid'];
		$this->app_secret = $app['appsecret'];
		if (!$this->getToken()) {
			E('获取ACCESS_TOKEN时出现问题，故障原因'.$this->getError());
		}
		$this->appDec();
	}
	
	private function appDec() {
		$map['appid'] = $this->appid;
		$map['request'] = array('gt', 0);
		$dec = M('WechatQuota')->where($map)->setDec('request');
		if (!$dec) {
			$this->error = '此公众号请求次数已经用完！';
		}
	}
	function send($openid, $content) {
		$url  = $this->apiUri.'message/custom/send?access_token='.$this->token;
		$data = array(
				'touser' => $openid,
				'msgtype'=> 'text',
				'text' => array('content' => $content)
		);
		$result = POST($url, $this->jsencode($data));
		$result = $this->praseJson($result);
		return $result;
	}
	
	/**
	 * 不转义中文字符和\/的 json 编码方法
	 * @param  string $arr
	 * @return string
	 */
	private function jsencode($arr) {
		$str = str_replace("\\/", "/", json_encode($arr));
		$search = '#\\\u([0-9a-f]+)#ie';
		if (strpos(strtoupper(PHP_OS), 'WIN' ) === false) {
			$replace = "iconv('UCS-2BE', 'UTF-8', pack('H4', '\\1'))";//LINUX
		} else {
			$replace = "iconv('UCS-2', 'UTF-8', pack('H4', '\\1'))";//WINDOWS
		}
		return preg_replace($search, $replace, $str );
	}
	/**
	 * 获取用户信息
	 * @param string $openid 用户openid
	 * @return array|boolean
	 */
	function user($openid) {
		$url  = $this->apiUri.'user/info';
		$data = array(
			'access_token' => $this->token,
			'lang'         => 'zh_CN',
			'openid'       => $openid
		);
		$jsonStr = GET($url, $data);
		$jsonArr = $this->praseJson($jsonStr);
		unset($jsonArr['subscribe']);
		if ($jsonArr) {
			return $jsonArr;
		}else {
			return false;
		}
	}
	
	/**
	 * 
	 * @return boolean
	 */
	function users() {
		$url  = $this->apiUri.'user/get';
		$data = array(
				'access_token' => $this->token,
		);
		$jsonStr = GET($url, $data);
		$jsonArr = $this->praseJson($jsonStr);
		if ($jsonArr) {
			$openId = (array)$jsonArr['data'];
			return $openId['openid'];
		}else {
			return false;
		}
	}
	
	/**
	 * 获取token
	 * @return boolean
	 */
	private function getToken() {
		//在数据库中查找token 如果没有token或者token过期，重新获取，并缓存
		$map['appid'] = $this->appid;
		$token = M('WechatToken')->where($map)->find();
		if (!$token || $token['expire_time'] < NOW_TIME) {
			if (!$this->getAccessToken()) {
				return false;
			}else {
				M('WechatToken')->where($map)->delete();
				$data['appid'] = $this->appid;
				$data['create_time'] = NOW_TIME;
				$data['expire_time'] = NOW_TIME + 7000;
				$data['token'] = $this->token;
				M('WechatToken')->add($data);
			}
		}else {
			$this->token = $token['token'];
		}
		return $this->token;
	}
	
	/**
	 * 从API获取ACCESS_TOKEN
	 * @return boolean
	 */
	private function getAccessToken() {
		$url  = $this->apiUri.'token';
		$data = array(
			'grant_type' => 'client_credential',
			'appid'      => $this->app_id,
			'secret'     => $this->app_secret
		);
		$jsonStr = GET($url, $data);
		if ($jsonStr) {
			$jsonArr = $this->praseJson($jsonStr);
			if ($jsonArr) {
				$this->token = $jsonArr['access_token'];
				return true;
			}else {
				return false;
			}
		}else {
			$this->error = '链接出错';
			return false;
		}
	}
	
	/**
	 * 解析JSON，如果有错误返回false并设置Error信息
	 */
	private function praseJson($jsonStr) {
		$arr = (array)json_decode($jsonStr);
		if (isset($arr['errcode'])) {
			if ($arr['errcode'] == 0) return true;
			$this->getErrorCode($arr['errcode']);
			return false;
		}else {
			return $arr;
		}
	}
	
	/**
	 * 捕获错误信息
	 * @return string
	 */
	function getError() {
		return $this->error;
	}
	
	/**
	 * /获取全局返回错误码
	 * @param unknown $code
	 */
	private function getErrorCode($code) {
		switch ($code) {
			case -1    : $this->error = '系统繁忙 '; break;
			case 40001 : $this->error = '获取access_token时AppSecret错误，或者access_token无效 '; break;
			case 40002 : $this->error = '不合法的凭证类型'; break;
			case 40003 : $this->error = '不合法的OpenID '; break;
			case 40004 : $this->error = '不合法的媒体文件类型'; break;
			case 40005 : $this->error = '不合法的文件类型'; break;
			case 40006 : $this->error = '不合法的文件大小'; break;
			case 40007 : $this->error = '不合法的媒体文件id '; break;
			case 40008 : $this->error = '不合法的消息类型 '; break;
			case 40009 : $this->error = '不合法的图片文件大小'; break;
			case 40010 : $this->error = '不合法的语音文件大小'; break;
			case 40011 : $this->error = '不合法的视频文件大小'; break;
			case 40012 : $this->error = '不合法的缩略图文件大小'; break;
			case 40013 : $this->error = '不合法的APPID'; break;
			case 40014 : $this->error = '不合法的access_token '; break;
			case 40015 : $this->error = '不合法的菜单类型 '; break;
			case 40016 : $this->error = '不合法的按钮个数 '; break;
			case 40017 : $this->error = '不合法的按钮个数'; break;
			case 40018 : $this->error = '不合法的按钮名字长度'; break;
			case 40019 : $this->error = '不合法的按钮KEY长度 '; break;
			case 40020 : $this->error = '不合法的按钮URL长度 '; break;
			case 40021 : $this->error = '不合法的菜单版本号'; break;
			case 40022 : $this->error = '不合法的子菜单级数'; break;
			case 40023 : $this->error = '不合法的子菜单按钮个数'; break;
			case 40024 : $this->error = '不合法的子菜单按钮类型'; break;
			case 40025 : $this->error = '不合法的子菜单按钮名字长度'; break;
			case 40026 : $this->error = '不合法的子菜单按钮KEY长度 '; break;
			case 40027 : $this->error = '不合法的子菜单按钮URL长度 '; break;
			case 40028 : $this->error = '不合法的自定义菜单使用用户'; break;
			case 40029 : $this->error = '不合法的oauth_code'; break;
			case 40030 : $this->error = '不合法的refresh_token'; break;
			case 40031 : $this->error = '不合法的openid列表 '; break;
			case 40032 : $this->error = '不合法的openid列表长度 '; break;
			case 40033 : $this->error = '不合法的请求字符，不能包含\uxxxx格式的字符 '; break;
			case 40035 : $this->error = '不合法的参数'; break;
			case 40038 : $this->error = '不合法的请求格式'; break;
			case 40039 : $this->error = '不合法的URL长度 '; break;
			case 40050 : $this->error = '不合法的分组id'; break;
			case 40051 : $this->error = '分组名字不合法'; break;
			case 41001 : $this->error = '缺少access_token参数'; break;
			case 41002 : $this->error = '缺少appid参数'; break;
			case 41003 : $this->error = '缺少refresh_token参数'; break;
			case 41004 : $this->error = '缺少secret参数'; break;
			case 41005 : $this->error = '缺少多媒体文件数据'; break;
			case 41006 : $this->error = '缺少media_id参数'; break;
			case 41007 : $this->error = '缺少子菜单数据'; break;
			case 41008 : $this->error = '缺少oauth code'; break;
			case 41009 : $this->error = '缺少openid'; break;
			case 42001 : $this->error = 'access_token超时'; break;
			case 42002 : $this->error = 'refresh_token超时'; break;
			case 42003 : $this->error = 'oauth_code超时'; break;
			case 43001 : $this->error = '需要GET请求'; break;
			case 43002 : $this->error = '需要POST请求'; break;
			case 43003 : $this->error = '需要HTTPS请求'; break;
			case 43004 : $this->error = '需要接收者关注'; break;
			case 43005 : $this->error = '需要好友关系'; break;
			case 44001 : $this->error = '多媒体文件为空'; break;
			case 44002 : $this->error = 'POST的数据包为空'; break;
			case 44003 : $this->error = '图文消息内容为空'; break;
			case 44004 : $this->error = '文本消息内容为空'; break;
			case 45001 : $this->error = '多媒体文件大小超过限制'; break;
			case 45002 : $this->error = '消息内容超过限制'; break;
			case 45003 : $this->error = '标题字段超过限制'; break;
			case 45004 : $this->error = '描述字段超过限制'; break;
			case 45005 : $this->error = '链接字段超过限制'; break;
			case 45006 : $this->error = '图片链接字段超过限制'; break;
			case 45007 : $this->error = '语音播放时间超过限制'; break;
			case 45008 : $this->error = '图文消息超过限制'; break;
			case 45009 : $this->error = '接口调用超过限制'; break;
			case 45010 : $this->error = '创建菜单个数超过限制'; break;
			case 45015 : $this->error = '回复时间超过限制'; break;
			case 45016 : $this->error = '系统分组，不允许修改'; break;
			case 45017 : $this->error = '分组名字过长'; break;
			case 45018 : $this->error = '分组数量超过上限'; break;
			case 46001 : $this->error = '不存在媒体数据'; break;
			case 46002 : $this->error = '不存在的菜单版本'; break;
			case 46003 : $this->error = '不存在的菜单数据'; break;
			case 46004 : $this->error = '不存在的用户'; break;
			case 47001 : $this->error = '解析JSON/XML内容错误'; break;
			case 48001 : $this->error = 'api功能未授权'; break;
			case 50001 : $this->error = '用户未授权该api'; break;
			default    : $this->error = '未知错误';
		}
	}
}